package com.youngjun.generator;


import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;

import java.io.*;
import java.sql.*;
import java.util.*;

/**
 * ref: <a href="https://blog.csdn.net/Melody_Susan/article/details/50826106" />
 * @author VirgoJun
 */

public class MybatisGenerator {

    private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22) {{
        //这里比较重要，用来指定加载模板所在的路径
        setTemplateLoader(new ClassTemplateLoader(getClass(), GeneratorConfig.TEMPLATE_PATH));
        setDefaultEncoding("UTF-8");
        setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        setCacheStorage(NullCacheStorage.INSTANCE);
    }};

    public static void main(String[] args) throws IOException, TemplateException {

        resolveTableInfo();

        boolean isGeneratorDomain = GeneratorConfig.IS_GENERATOR_DOMAIN;
        boolean isGeneratorDTO = GeneratorConfig.IS_GENERATOR_DTO;
        boolean isGeneratorVO = GeneratorConfig.IS_GENERATOR_VO;
        boolean isGeneratorMapper = GeneratorConfig.IS_GENERATOR_MAPPER;
        boolean isGeneratorMapperXml = GeneratorConfig.IS_GENERATOR_MAPPER_XML;
        boolean isGeneratorService = GeneratorConfig.IS_GENERATOR_SERVICE;
        boolean isGeneratorServiceImpl = GeneratorConfig.IS_GENERATOR_SERVICE_IMPL;
        boolean isGeneratorController = GeneratorConfig.IS_GENERATOR_CONTROLLER;

        if (isGeneratorDomain) {
            for (Table table : GeneratorConfig.TABLES) {
                Template template = CONFIGURATION.getTemplate(table.getConfig().getDomainTpl());
                FileOutputStream outputStream = new FileOutputStream(new File(getOrMakeDir(GeneratorConfig.JAVA_OUT_PATH, table.getConfig().getDomainPackage().replaceAll("\\.", "\\/")), table.getJavaDomainName() + table.getConfig().getDomainNameSuffix() + ".java"));
                Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"), 10240);
                template.process(table, writer);
            }
        }
        if (isGeneratorDTO) {
            for (Table table : GeneratorConfig.TABLES) {
                Template template = CONFIGURATION.getTemplate(table.getConfig().getDtoTpl());
                FileOutputStream outputStream = new FileOutputStream(new File(getOrMakeDir(GeneratorConfig.JAVA_OUT_PATH, table.getConfig().getDtoPackage().replaceAll("\\.", "\\/")), table.getJavaDomainName() + table.getConfig().getDtoNameSuffix() + ".java"));
                Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"), 10240);
                template.process(table, writer);
            }
        }
        if (isGeneratorVO) {
        }
        if (isGeneratorMapper) {
            for (Table table : GeneratorConfig.TABLES) {
                Template template = CONFIGURATION.getTemplate(table.getConfig().getMapperTpl());
                FileOutputStream outputStream = new FileOutputStream(new File(getOrMakeDir(GeneratorConfig.JAVA_OUT_PATH, table.getConfig().getMapperPackage().replaceAll("\\.", "\\/")), table.getJavaDomainName() + table.getConfig().getMapperXmlNameSuffix() + ".java"));
                Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"), 10240);
                template.process(table, writer);
            }
        }
        if (isGeneratorMapperXml) {
            for (Table table : GeneratorConfig.TABLES) {
                Template template = CONFIGURATION.getTemplate(table.getConfig().getMapperXmlTpl());
                FileOutputStream outputStream = new FileOutputStream(new File(getOrMakeDir(GeneratorConfig.XML_OUT_PATH, table.getConfig().getMapperXmlPath()), table.getJavaDomainName() + table.getConfig().getMapperNameSuffix() + ".xml"));
                Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"), 10240);
                template.process(table, writer);
            }
        }
        if (isGeneratorService) {
            for (Table table : GeneratorConfig.TABLES) {
                Template template = CONFIGURATION.getTemplate(table.getConfig().getServiceNameTpl());
                FileOutputStream outputStream = new FileOutputStream(new File(getOrMakeDir(GeneratorConfig.JAVA_OUT_PATH, table.getConfig().getServicePackage().replaceAll("\\.", "\\/")), table.getJavaDomainName() + table.getConfig().getServiceNameSuffix() + ".java"));
                Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"), 10240);
                template.process(table, writer);
            }
        }
        if (isGeneratorServiceImpl) {
            for (Table table : GeneratorConfig.TABLES) {
                Template template = CONFIGURATION.getTemplate(table.getConfig().getServiceImplTpl());
                FileOutputStream outputStream = new FileOutputStream(new File(getOrMakeDir(GeneratorConfig.JAVA_OUT_PATH, table.getConfig().getServiceImplPackage().replaceAll("\\.", "\\/")), table.getJavaDomainName() + table.getConfig().getServiceImplNameSuffix() + ".java"));
                Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"), 10240);
                template.process(table, writer);
            }
        }
        if (isGeneratorController) {
            for (Table table : GeneratorConfig.TABLES) {
                Template template = CONFIGURATION.getTemplate(table.getConfig().getControllerNameTpl());
                FileOutputStream outputStream = new FileOutputStream(new File(getOrMakeDir(GeneratorConfig.JAVA_OUT_PATH, table.getConfig().getControllerPackage().replaceAll("\\.", "\\/")), table.getJavaDomainName() + table.getConfig().getControllerNameSuffix() + ".java"));
                Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"), 10240);
                template.process(table, writer);
            }
        }


    }

    private static Connection getConnection() throws RuntimeException {
        try {
            Class.forName(GeneratorConfig.DRIVER);
            return DriverManager.getConnection(GeneratorConfig.URL, GeneratorConfig.USER, GeneratorConfig.PASSWORD);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    private static void resolveTableInfo() {
        try (Connection connection = getConnection()) {
            DatabaseMetaData databaseMetaData = connection.getMetaData();

            for (Table table : GeneratorConfig.TABLES) {
                ResultSet tableSet = databaseMetaData.getTables(null, "%", table.getTableName(), null);
                while (tableSet.next()) {
                    table.setTableRemarkes(tableSet.getString("REMARKS"));
                }

                ResultSet resultSet = databaseMetaData.getColumns(null, "%", table.getTableName(), "%");
                Set<String> importClassNames = new HashSet<>();
                List<Column> columnList = new ArrayList<>();
                while (resultSet.next()) {
                    //id字段略过
//                    if (resultSet.getString("COLUMN_NAME").equals("id")) continue;
                    Column column = new Column();
                    //获取字段名称
                    column.setColumnName(resultSet.getString("COLUMN_NAME"));
                    //获取字段类型
                    column.setColumnType(resultSet.getString("TYPE_NAME"));

                    column.setColumnSize(resultSet.getInt("COLUMN_SIZE"));
                    column.setDecimalDigits(resultSet.getInt("DECIMAL_DIGITS"));
                    //转换字段名称，如 sys_name 变成 SysName
                    column.setJavaFieldName(StringUtils.camelCase(column.getColumnName()));
                    column.setJavaFieldNameCapitalize(StringUtils.capitalize(column.getColumnName()));
                    column.setJavaFieldType(JavaFieldTypeConverter.parse(column.getColumnType(), column.getColumnSize(), column.getDecimalDigits()));
                    //字段在数据库的注释
                    column.setColumnComment(resultSet.getString("REMARKS"));
                    columnList.add(column);

                    String javaFieldClassName = column.getJavaFieldType().getClassName();

                    //是否需要导入包
                    boolean isNeedImportClassName = (!javaFieldClassName.startsWith("java.lang."))
                            || !(Arrays
                            .stream(GeneratorConfig.NOT_NEED_IMPORT_CLASS_NAMES)
                            .noneMatch(item -> item.equals(javaFieldClassName)));

                    if (isNeedImportClassName) {
                        importClassNames.add(javaFieldClassName);
                    }

                }
                table.setImportClassNames(importClassNames);
                table.setColumns(columnList);

            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    private static File getOrMakeDir(String... paths) {
        File file = null;
        for (int i = 0; i < paths.length; i++) {
            if (file == null) {
                file = new File(paths[i]);
            } else {
                file = new File(file.getPath(), paths[i]);
            }
        }
        if (file != null) {
            file.mkdirs();
        }
        return file;
    }

    private static void println(Object obj) {
        System.out.println(obj);
    }

}
